In [1]:
#!pip install tensorflow
In [1]:
import tensorflow as tf
from tensorflow.keras import models, layers
import matplotlib.pyplot as plt
In [2]:
imageSize = 256   # Setting the image size as that of properties
batchSize = 32    # Making a group of 32 images
channels = 3      # RGB values
epochs = 10       # 
In [3]:
#Potato plant
potato_dataset = tf.keras.preprocessing.image_dataset_from_directory(
    "PotatoPlant",
    shuffle=True,
    image_size = (imageSize,imageSize),
    batch_size = batchSize
)
Found 2152 files belonging to 3 classes.
In [4]:
class_names = potato_dataset.class_names
class_names   #Names of folder present in PotatoPlant
Out[4]:
['Potato___Early_blight', 'Potato___Late_blight', 'Potato___healthy']
In [5]:
len(potato_dataset)
Out[5]:
68
In [6]:
68*32    #length of dataset and batch size
Out[6]:
2176
In [7]:
for image_batch, label_batch in potato_dataset.take(1):
    print(image_batch.shape)
    print(label_batch.numpy())
#Basically it provides a batch size, image size and RGB channels
#label batch signifies the class number
(32, 256, 256, 3)
[1 1 1 0 1 1 0 0 0 1 0 1 1 0 0 0 1 0 0 2 0 0 1 2 0 1 1 1 0 1 1 0]
In [8]:
plt.figure(figsize=(10, 10))
for image_batch, label_batch in potato_dataset.take(1):
    for i in range(16):    #here in range max value we can give is 32 bcoz batch size is 32
        ax = plt.subplot(4, 4, i + 1)
        plt.imshow(image_batch[i].numpy().astype("uint8"))
        plt.title(class_names[label_batch[i]])
        plt.axis("off")
In [9]:
len(potato_dataset)
Out[9]:
68
In [10]:
# 70% -> Training dataset
# 15% -> Validation dataset
# 15% -> Testing dataset
train_size = 0.7
len(potato_dataset)*train_size
Out[10]:
47.599999999999994
In [11]:
train_potatodataset = potato_dataset.take(47)   # Considering first 47 values
len(train_potatodataset)
Out[11]:
47
In [12]:
test_potatodataset = potato_dataset.skip(47)    # Considering values after 47
len(test_potatodataset)
Out[12]:
21
In [13]:
validation_size = 0.15
len(potato_dataset)*validation_size
Out[13]:
10.2
In [14]:
validation_potatodataset = test_potatodataset.take(10)
len(validation_potatodataset)
Out[14]:
10
In [15]:
test_potatodataset = test_potatodataset.skip(10)
len(test_potatodataset)
Out[15]:
11
In [16]:
def get_dataset_partitions_tf(ds, train_split = 0.7, val_split = 0.15, test_split = 0.15, shuffle=True, shuffle_size=10000):
    if shuffle:
        ds = ds.shuffle(shuffle_size, seed = 15)
        
    ds_size = len(ds)
    train_size = int(train_split*ds_size)
    val_size = int(val_split*ds_size)
    test_size = int(test_split*ds_size)
    
    train_ds = ds.take(train_size)
    validation_ds = ds.skip(train_size).take(val_size)
    test_ds = ds.skip(train_size).skip(val_size)
    
    return train_ds, validation_ds, test_ds
In [17]:
train_ds, validation_ds, test_ds = get_dataset_partitions_tf(potato_dataset)
In [18]:
print(len(train_ds))
print(len(validation_ds))
print(len(test_ds))
47
10
11
In [19]:
# Here cache is used to store the image so that we can read the image from the disk which improves the performance.
# Prefetch is used because if GPU is busy with training purpose meanwhile CPU will read the next batch so that the performance is optimized.
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
validation_ds = validation_ds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
test_ds = test_ds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
#Thus we get the optimized Training, Validation and Testing dataset.
In [20]:
#Data preprocessing
resize_and_rescale = tf.keras.Sequential([
    layers.experimental.preprocessing.Resizing(imageSize, imageSize),   #Suppose if the size of image is not 256 then this will take care of that.
    layers.experimental.preprocessing.Rescaling(1.0/255)   #Rescaling the image to 255 and supply the layer when we actually build our model.
])
In [21]:
#Data augmentation :- Techniques used to increase the amount of data by adding slightly modified copies of already existing data
data_augmentation = tf.keras.Sequential([
    layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
    layers.experimental.preprocessing.RandomRotation(0.2)
])
#We just created layers for preprocessing and we will this layer in our actual model.
In [22]:
input_shape = (batchSize, imageSize, imageSize, channels)
n_classes = 3

model = models.Sequential([
    resize_and_rescale,
    layers.Conv2D(32, kernel_size = (3,3), activation='relu', input_shape=input_shape),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(n_classes, activation='softmax'), #softmax function -> normalize the probability of your classes.
])

model.build(input_shape=input_shape)
In [23]:
model.summary()
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 sequential (Sequential)     (32, 256, 256, 3)         0         
                                                                 
 conv2d (Conv2D)             (32, 254, 254, 32)        896       
                                                                 
 max_pooling2d (MaxPooling2D  (32, 127, 127, 32)       0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (32, 125, 125, 64)        18496     
                                                                 
 max_pooling2d_1 (MaxPooling  (32, 62, 62, 64)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (32, 60, 60, 64)          36928     
                                                                 
 max_pooling2d_2 (MaxPooling  (32, 30, 30, 64)         0         
 2D)                                                             
                                                                 
 conv2d_3 (Conv2D)           (32, 28, 28, 64)          36928     
                                                                 
 max_pooling2d_3 (MaxPooling  (32, 14, 14, 64)         0         
 2D)                                                             
                                                                 
 conv2d_4 (Conv2D)           (32, 12, 12, 64)          36928     
                                                                 
 max_pooling2d_4 (MaxPooling  (32, 6, 6, 64)           0         
 2D)                                                             
                                                                 
 conv2d_5 (Conv2D)           (32, 4, 4, 64)            36928     
                                                                 
 max_pooling2d_5 (MaxPooling  (32, 2, 2, 64)           0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (32, 256)                 0         
                                                                 
 dense (Dense)               (32, 64)                  16448     
                                                                 
 dense_1 (Dense)             (32, 3)                   195       
                                                                 
=================================================================
Total params: 183,747
Trainable params: 183,747
Non-trainable params: 0
_________________________________________________________________
In [24]:
model.compile(
        optimizer = 'adam',
        loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits = False),
        metrics = ['accuracy']   #to track the gradient descent/ training process.
)
In [25]:
epochs = 10
results = model.fit(
    train_ds,
    batch_size=batchSize,
    validation_data=validation_ds,
    verbose=1,
    epochs=epochs,
)
Epoch 1/10
47/47 [==============================] - 55s 1s/step - loss: 0.8916 - accuracy: 0.5264 - val_loss: 0.7920 - val_accuracy: 0.6375
Epoch 2/10
47/47 [==============================] - 58s 1s/step - loss: 0.6598 - accuracy: 0.7081 - val_loss: 0.4373 - val_accuracy: 0.8031
Epoch 3/10
47/47 [==============================] - 59s 1s/step - loss: 0.3786 - accuracy: 0.8372 - val_loss: 0.2665 - val_accuracy: 0.8750
Epoch 4/10
47/47 [==============================] - 57s 1s/step - loss: 0.3530 - accuracy: 0.8635 - val_loss: 0.2546 - val_accuracy: 0.8938
Epoch 5/10
47/47 [==============================] - 56s 1s/step - loss: 0.2875 - accuracy: 0.8851 - val_loss: 0.1862 - val_accuracy: 0.9312
Epoch 6/10
47/47 [==============================] - 55s 1s/step - loss: 0.2321 - accuracy: 0.9095 - val_loss: 0.1880 - val_accuracy: 0.9187
Epoch 7/10
47/47 [==============================] - 54s 1s/step - loss: 0.2386 - accuracy: 0.9027 - val_loss: 0.1518 - val_accuracy: 0.9375
Epoch 8/10
47/47 [==============================] - 54s 1s/step - loss: 0.1902 - accuracy: 0.9216 - val_loss: 0.2473 - val_accuracy: 0.9094
Epoch 9/10
47/47 [==============================] - 54s 1s/step - loss: 0.1596 - accuracy: 0.9419 - val_loss: 0.1149 - val_accuracy: 0.9563
Epoch 10/10
47/47 [==============================] - 54s 1s/step - loss: 0.1382 - accuracy: 0.9446 - val_loss: 0.0879 - val_accuracy: 0.9656
In [26]:
scores = model.evaluate(test_ds) #Testing accuracy
11/11 [==============================] - 3s 218ms/step - loss: 0.1211 - accuracy: 0.9460
In [27]:
scores      #returns loss and accuracy
Out[27]:
[0.1210547462105751, 0.9460227489471436]
In [28]:
results   #history
Out[28]:
<keras.callbacks.History at 0x2037d806790>
In [29]:
results.params
Out[29]:
{'verbose': 1, 'epochs': 10, 'steps': 47}
In [30]:
results.history.keys()
Out[30]:
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
In [31]:
accuracy = results.history['accuracy']
val_accuracy = results.history['val_accuracy']
loss = results.history['loss']
val_loss = results.history['val_loss']
In [33]:
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(range(epochs), accuracy, label='Training Accuracy')
plt.plot(range(epochs), val_accuracy, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(range(epochs), loss, label='Training Loss')
plt.plot(range(epochs), val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
In [34]:
import numpy as np
for images_batch, labels_batch in test_ds.take(1):    # where 1 is the number of batches
    #print(images_batch[0])    #Tensor format
    #print(images_batch[0].numpy())     #Numpy format
    #plt.imshow(images_batch[0].numpy().astype('uint8'))    #Displays the actual image
    first_image = images_batch[0].numpy().astype('uint8')
    first_label = labels_batch[0].numpy()
    
    print("Predicting the first image")
    plt.imshow(first_image)
    print("Actual class label:",class_names[first_label])
    
    batch_prediction = model.predict(images_batch)
    print("Predicted class label:",class_names[np.argmax(batch_prediction[0])])
Predicting the first image
Actual class label: Potato___Early_blight
Predicted class label: Potato___Early_blight
In [35]:
#Creating a function for inference
def predict_model(model, img):
    img_array = tf.keras.preprocessing.image.img_to_array(images[i].numpy())
    img_array = tf.expand_dims(img_array, 0)
    predictions = model.predict(img_array)
    predicted_class = class_names[np.argmax(predictions[0])]
    confidence = round(100 * (np.max(predictions[0])), 2)
    return predicted_class, confidence
In [36]:
#Running the inference on few sample images
plt.figure(figsize=(15, 15))
for images, labels in test_ds.take(1):   #Taking 1 batch
    for i in range(9):    #Considering 9 images at a time
        ax = plt.subplot(3, 3, i + 1)
        plt.imshow(images[i].numpy().astype("uint8"))
        
        predicted_class, confidence = predict_model(model, images[i].numpy())
        actual_class = class_names[labels[i]] 
        
        plt.title(f"Actual class label: {actual_class},\n Predicted class label: {predicted_class}.\n Confidence: {confidence}%")
        plt.axis("off")   #Removing the axes
In [37]:
import os
model_version=max([int(i) for i in os.listdir("saved_models/") + [0]])+1
model.save(f"./saved_models/{model_version}")
INFO:tensorflow:Assets written to: ./saved_models/2\assets
In [38]:
#imageSize = 256   
#batchSize = 32    
#channels = 3      
#epochs = 50 

#BellPepper plant
bellpepper_dataset = tf.keras.preprocessing.image_dataset_from_directory(
    "BellPepperPlant",
    shuffle=True,
    image_size = (imageSize,imageSize),
    batch_size = batchSize
)
Found 2475 files belonging to 2 classes.
In [39]:
bellpepper_class_names = bellpepper_dataset.class_names
bellpepper_class_names   #Names of folder present in BellPepperPlant
Out[39]:
['Pepper__bell___Bacterial_spot', 'Pepper__bell___healthy']
In [40]:
len(bellpepper_dataset)
Out[40]:
78
In [41]:
78*32
Out[41]:
2496
In [42]:
for image_batch, label_batch in bellpepper_dataset.take(1):
    print(image_batch.shape)
    print(label_batch.numpy())
#Basically it provides a batch size, image size and RGB channels
#label batch signifies the class number
(32, 256, 256, 3)
[0 1 0 1 0 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 1 0 0 0 1 0 0]
In [43]:
plt.figure(figsize=(10, 10))
for image_batch, label_batch in bellpepper_dataset.take(1):
    for i in range(9):    #here in range max value we can give is 32 bcoz batch size is 32
        ax = plt.subplot(3, 3, i + 1)
        plt.imshow(image_batch[i].numpy().astype("uint8"))
        plt.title(bellpepper_class_names[label_batch[i]])
        plt.axis("off")
In [44]:
len(bellpepper_dataset)
Out[44]:
78
In [45]:
# 70% -> Training dataset
# 15% -> Validation dataset
# 15% -> Testing dataset
train_size = 0.7
len(bellpepper_dataset)*train_size
Out[45]:
54.599999999999994
In [46]:
train_bellpepperdataset = bellpepper_dataset.take(54)   # Considering first 54 values
len(train_bellpepperdataset)
Out[46]:
54
In [47]:
test_bellpepperdataset = bellpepper_dataset.skip(54)   # Considering values after 54
len(test_bellpepperdataset)
Out[47]:
24
In [48]:
validation_size = 0.15
len(bellpepper_dataset)*validation_size
Out[48]:
11.7
In [49]:
validation_bellpepperdataset = test_bellpepperdataset.take(11)
len(validation_bellpepperdataset)
Out[49]:
11
In [50]:
test_bellpepperdataset = test_bellpepperdataset.skip(11)
len(test_bellpepperdataset)
Out[50]:
13
In [51]:
train_bellpepperds, validation_bellpepperds, test_bellpepperds = get_dataset_partitions_tf(bellpepper_dataset)
In [52]:
print(len(train_bellpepperds))
print(len(validation_bellpepperds))
print(len(test_bellpepperds))
54
11
13
In [53]:
# Here cache is used to store the image so that we can read the image from the disk which improves the performance.
# Prefetch is used because if GPU is busy with training purpose meanwhile CPU will read the next batch so that the performance is optimized.
train_bellpepperds = train_bellpepperds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
validation_bellpepperds = validation_bellpepperds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
test_bellpepperds = test_bellpepperds.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
#Thus we get the optimized Training, Validation and Testing dataset.
In [54]:
#Data preprocessing
resize_and_rescale = tf.keras.Sequential([
    layers.experimental.preprocessing.Resizing(imageSize, imageSize),   #Supose if the size of image is not 256 then this will take care of that.
    layers.experimental.preprocessing.Rescaling(1.0/255)   #Rescaling the image to 255 and supply the layer when we actually build our model.
])
In [55]:
#Data augmentation :- Techniques used to increase the amount of data by adding slightly modified copies of already existing data
data_augmentation = tf.keras.Sequential([
    layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
    layers.experimental.preprocessing.RandomRotation(0.2)
])
#We just created layers for preprocessing and we will this layer in our actual model.
In [56]:
input_shape = (batchSize, imageSize, imageSize, channels)
n_classes = 2

model = models.Sequential([
    resize_and_rescale,
    layers.Conv2D(32, kernel_size = (3,3), activation='relu', input_shape=input_shape),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(n_classes, activation='softmax'), #softmax function -> normalize the probability of your classes.
])

model.build(input_shape=input_shape)
In [57]:
model.summary()
Model: "sequential_5"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 sequential_3 (Sequential)   (32, 256, 256, 3)         0         
                                                                 
 conv2d_6 (Conv2D)           (32, 254, 254, 32)        896       
                                                                 
 max_pooling2d_6 (MaxPooling  (32, 127, 127, 32)       0         
 2D)                                                             
                                                                 
 conv2d_7 (Conv2D)           (32, 125, 125, 64)        18496     
                                                                 
 max_pooling2d_7 (MaxPooling  (32, 62, 62, 64)         0         
 2D)                                                             
                                                                 
 conv2d_8 (Conv2D)           (32, 60, 60, 64)          36928     
                                                                 
 max_pooling2d_8 (MaxPooling  (32, 30, 30, 64)         0         
 2D)                                                             
                                                                 
 conv2d_9 (Conv2D)           (32, 28, 28, 64)          36928     
                                                                 
 max_pooling2d_9 (MaxPooling  (32, 14, 14, 64)         0         
 2D)                                                             
                                                                 
 conv2d_10 (Conv2D)          (32, 12, 12, 64)          36928     
                                                                 
 max_pooling2d_10 (MaxPoolin  (32, 6, 6, 64)           0         
 g2D)                                                            
                                                                 
 conv2d_11 (Conv2D)          (32, 4, 4, 64)            36928     
                                                                 
 max_pooling2d_11 (MaxPoolin  (32, 2, 2, 64)           0         
 g2D)                                                            
                                                                 
 flatten_1 (Flatten)         (32, 256)                 0         
                                                                 
 dense_2 (Dense)             (32, 64)                  16448     
                                                                 
 dense_3 (Dense)             (32, 2)                   130       
                                                                 
=================================================================
Total params: 183,682
Trainable params: 183,682
Non-trainable params: 0
_________________________________________________________________
In [58]:
model.compile(
        optimizer = 'adam',
        loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits = False),
        metrics = ['accuracy']   #to track the gradient descent/ training process.
)
In [59]:
epochs = 10
results = model.fit(
    train_bellpepperds,
    batch_size=batchSize,
    validation_data=validation_bellpepperds,
    verbose=1,
    epochs=epochs,
)
Epoch 1/10
54/54 [==============================] - 63s 1s/step - loss: 0.5557 - accuracy: 0.7001 - val_loss: 0.3482 - val_accuracy: 0.8835
Epoch 2/10
54/54 [==============================] - 60s 1s/step - loss: 0.3010 - accuracy: 0.8981 - val_loss: 0.3077 - val_accuracy: 0.8608
Epoch 3/10
54/54 [==============================] - 60s 1s/step - loss: 0.2527 - accuracy: 0.9320 - val_loss: 0.1030 - val_accuracy: 0.9545
Epoch 4/10
54/54 [==============================] - 60s 1s/step - loss: 0.1236 - accuracy: 0.9566 - val_loss: 0.0700 - val_accuracy: 0.9773
Epoch 5/10
54/54 [==============================] - 60s 1s/step - loss: 0.0799 - accuracy: 0.9766 - val_loss: 0.0243 - val_accuracy: 0.9943
Epoch 6/10
54/54 [==============================] - 60s 1s/step - loss: 0.0361 - accuracy: 0.9871 - val_loss: 0.0156 - val_accuracy: 0.9915
Epoch 7/10
54/54 [==============================] - 60s 1s/step - loss: 0.0301 - accuracy: 0.9912 - val_loss: 0.0712 - val_accuracy: 0.9801
Epoch 8/10
54/54 [==============================] - 60s 1s/step - loss: 0.0639 - accuracy: 0.9836 - val_loss: 0.0187 - val_accuracy: 0.9943
Epoch 9/10
54/54 [==============================] - 60s 1s/step - loss: 0.0668 - accuracy: 0.9801 - val_loss: 0.0090 - val_accuracy: 0.9943
Epoch 10/10
54/54 [==============================] - 60s 1s/step - loss: 0.0193 - accuracy: 0.9965 - val_loss: 0.0650 - val_accuracy: 0.9773
In [60]:
scores = model.evaluate(test_bellpepperds)
13/13 [==============================] - 4s 227ms/step - loss: 0.0766 - accuracy: 0.9688
In [61]:
scores      #returns loss and accuracy
Out[61]:
[0.07658757269382477, 0.96875]
In [62]:
results     #history
Out[62]:
<keras.callbacks.History at 0x1e13d140a90>
In [63]:
results.params
Out[63]:
{'verbose': 1, 'epochs': 10, 'steps': 54}
In [64]:
results.history.keys()
Out[64]:
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
In [65]:
accuracy = results.history['accuracy']
val_accuracy = results.history['val_accuracy']
loss = results.history['loss']
val_loss = results.history['val_loss']
In [66]:
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(range(epochs), accuracy, label='Training Accuracy')
plt.plot(range(epochs), val_accuracy, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(range(epochs), loss, label='Training Loss')
plt.plot(range(epochs), val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
In [67]:
import numpy as np
for images_batch, labels_batch in test_bellpepperds.take(1):    # where 1 is the number of batches
    #print(images_batch[0])    #Tensor format
    #print(images_batch[0].numpy())     #Numpy format
    #plt.imshow(images_batch[0].numpy().astype('uint8'))    #Displays the actual image
    first_image = images_batch[0].numpy().astype('uint8')
    first_label = labels_batch[0].numpy()
    
    print("Predicting the first image")
    plt.imshow(first_image)
    print("Actual class label:",bellpepper_class_names[first_label])
    
    batch_prediction = model.predict(images_batch)
    print("Predicted class label:",bellpepper_class_names[np.argmax(batch_prediction[0])])
Predicting the first image
Actual class label: Pepper__bell___healthy
Predicted class label: Pepper__bell___healthy
In [68]:
#Creating a function for inference
def predict_model(model, img):
    img_array = tf.keras.preprocessing.image.img_to_array(images[i].numpy())
    img_array = tf.expand_dims(img_array, 0)
    predictions = model.predict(img_array)
    predicted_class = bellpepper_class_names[np.argmax(predictions[0])]
    confidence = round(100 * (np.max(predictions[0])), 2)
    return predicted_class, confidence
In [69]:
#Running the inference on few sample images
plt.figure(figsize=(15, 15))
for images, labels in test_bellpepperds.take(1):   #Taking 1 batch
    for i in range(6):    #Considering 9 images at a time
        ax = plt.subplot(3, 2, i + 1)
        plt.imshow(images[i].numpy().astype("uint8"))
        
        predicted_class, confidence = predict_model(model, images[i].numpy())
        actual_class = bellpepper_class_names[labels[i]] 
        
        plt.title(f"Actual class label: {actual_class},\n Predicted class label: {predicted_class}.\n Confidence: {confidence}%")
        plt.axis("off")   #Removing the axes
In [3]:
imageSize = 256   
batchSize = 32    
channels = 3      
epochs = 10

#Tomato Plant
tomato_dataset = tf.keras.preprocessing.image_dataset_from_directory(
    "tomatoPlant",
    shuffle=True,
    image_size = (imageSize,imageSize),
    batch_size = batchSize
)
Found 16011 files belonging to 10 classes.
In [4]:
class_names_tomato = tomato_dataset.class_names
class_names_tomato   #Names of folder present in PotatoPlant
Out[4]:
['Tomato_Bacterial_spot',
 'Tomato_Early_blight',
 'Tomato_Late_blight',
 'Tomato_Leaf_Mold',
 'Tomato_Septoria_leaf_spot',
 'Tomato_Spider_mites_Two_spotted_spider_mite',
 'Tomato__Target_Spot',
 'Tomato__Tomato_YellowLeaf__Curl_Virus',
 'Tomato__Tomato_mosaic_virus',
 'Tomato_healthy']
In [5]:
len(tomato_dataset)
Out[5]:
501
In [6]:
501*32
Out[6]:
16032
In [7]:
for image_batch, label_batch in tomato_dataset.take(1):   #Considering 1 batch at a time
    print(image_batch.shape)
    print(label_batch.numpy())
#Basically it provides a batch size, image size and RGB channels
#label batch signifies the class number
(32, 256, 256, 3)
[2 2 3 7 7 7 5 6 4 4 5 5 7 6 0 6 4 0 6 7 3 6 7 7 7 5 7 6 2 2 4 0]
In [8]:
plt.figure(figsize=(10, 10))
for image_batch, label_batch in tomato_dataset.take(1):
    for i in range(9):    #here in range max value we can give is 32 bcoz batch size is 32
        ax = plt.subplot(3, 3, i + 1)
        plt.imshow(image_batch[i].numpy().astype("uint8"))
        plt.title(class_names_tomato[label_batch[i]])
        plt.axis("off")
In [9]:
len(tomato_dataset)
Out[9]:
501
In [10]:
# 70% -> Training dataset
# 15% -> Validation dataset
# 15% -> Testing dataset
train_size = 0.7
len(tomato_dataset)*train_size
Out[10]:
350.7
In [11]:
train_tomatodataset = tomato_dataset.take(350)   # Considering first 350 values
len(train_tomatodataset)
Out[11]:
350
In [12]:
test_tomatodataset = tomato_dataset.skip(350)    # Considering values after 350
len(test_tomatodataset)
Out[12]:
151
In [13]:
validation_size = 0.15
len(tomato_dataset)*validation_size
Out[13]:
75.14999999999999
In [14]:
validation_potatodataset = test_tomatodataset.take(75)    
len(validation_potatodataset)
Out[14]:
75
In [18]:
test_tomatodataset = test_tomatodataset.skip(75)
len(test_tomatodataset)
Out[18]:
1
In [19]:
train_tomatods, validation_tomatods, test_tomatods = get_dataset_partitions_tf(tomato_dataset)
In [20]:
print(len(train_tomatods))
print(len(validation_tomatods))
print(len(test_tomatods))
350
75
76
In [21]:
# Here cache is used to store the image so that we can read the image from the disk which improves the performance.
# Prefetch is used because if GPU is busy with training purpose meanwhile CPU will read the next batch so that the performance is optimized.
train_tomatods = train_tomatods.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
validation_tomatods = validation_tomatods.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
test_tomatods = test_tomatods.cache().shuffle(1000).prefetch(buffer_size = tf.data.AUTOTUNE)
#Thus we get the optimized Training, Validation and Testing dataset.
In [22]:
#Data preprocessing
resize_and_rescale = tf.keras.Sequential([
    layers.experimental.preprocessing.Resizing(imageSize, imageSize),   #Supose if the size of image is not 256 then this will take care of that.
    layers.experimental.preprocessing.Rescaling(1.0/255)   #Rescaling the image to 255 and supply the layer when we actually build our model.
])
In [23]:
#Data augmentation :- Techniques used to increase the amount of data by adding slightly modified copies of already existing data
data_augmentation = tf.keras.Sequential([
    layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
    layers.experimental.preprocessing.RandomRotation(0.2)ss
])
#We just created layers for preprocessing and we will this layer in our actual model.
In [24]:
input_shape = (batchSize, imageSize, imageSize, channels)
n_classes = 10

model = models.Sequential([
    resize_and_rescale,
    layers.Conv2D(32, kernel_size = (3,3), activation='relu', input_shape=input_shape),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64,  kernel_size = (3,3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(n_classes, activation='softmax'), #softmax function -> normalize the probability of your classes.
])

model.build(input_shape=input_shape)
In [25]:
model.summary()
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 sequential (Sequential)     (32, 256, 256, 3)         0         
                                                                 
 conv2d (Conv2D)             (32, 254, 254, 32)        896       
                                                                 
 max_pooling2d (MaxPooling2D  (32, 127, 127, 32)       0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (32, 125, 125, 64)        18496     
                                                                 
 max_pooling2d_1 (MaxPooling  (32, 62, 62, 64)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (32, 60, 60, 64)          36928     
                                                                 
 max_pooling2d_2 (MaxPooling  (32, 30, 30, 64)         0         
 2D)                                                             
                                                                 
 conv2d_3 (Conv2D)           (32, 28, 28, 64)          36928     
                                                                 
 max_pooling2d_3 (MaxPooling  (32, 14, 14, 64)         0         
 2D)                                                             
                                                                 
 conv2d_4 (Conv2D)           (32, 12, 12, 64)          36928     
                                                                 
 max_pooling2d_4 (MaxPooling  (32, 6, 6, 64)           0         
 2D)                                                             
                                                                 
 conv2d_5 (Conv2D)           (32, 4, 4, 64)            36928     
                                                                 
 max_pooling2d_5 (MaxPooling  (32, 2, 2, 64)           0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (32, 256)                 0         
                                                                 
 dense (Dense)               (32, 64)                  16448     
                                                                 
 dense_1 (Dense)             (32, 10)                  650       
                                                                 
=================================================================
Total params: 184,202
Trainable params: 184,202
Non-trainable params: 0
_________________________________________________________________
In [26]:
model.compile(
        optimizer = 'adam',
        loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits = False),
        metrics = ['accuracy']   #to track the gradient descent/ training process.
)
In [27]:
epochs = 10
results_tomato = model.fit(
    train_tomatods,
    batch_size=batchSize,
    validation_data=validation_tomatods,
    verbose=1,
    epochs=epochs,
)
Epoch 1/10
350/350 [==============================] - 483s 1s/step - loss: 1.5806 - accuracy: 0.4277 - val_loss: 0.9397 - val_accuracy: 0.6700
Epoch 2/10
350/350 [==============================] - 425s 1s/step - loss: 0.8190 - accuracy: 0.7087 - val_loss: 0.5956 - val_accuracy: 0.7967
Epoch 3/10
350/350 [==============================] - 394s 1s/step - loss: 0.5225 - accuracy: 0.8142 - val_loss: 0.5039 - val_accuracy: 0.8204
Epoch 4/10
350/350 [==============================] - 397s 1s/step - loss: 0.4050 - accuracy: 0.8572 - val_loss: 0.3708 - val_accuracy: 0.8683
Epoch 5/10
350/350 [==============================] - 394s 1s/step - loss: 0.3030 - accuracy: 0.8992 - val_loss: 0.2658 - val_accuracy: 0.9100
Epoch 6/10
350/350 [==============================] - 394s 1s/step - loss: 0.2502 - accuracy: 0.9132 - val_loss: 0.2079 - val_accuracy: 0.9296
Epoch 7/10
350/350 [==============================] - 394s 1s/step - loss: 0.2135 - accuracy: 0.9260 - val_loss: 0.2483 - val_accuracy: 0.9167
Epoch 8/10
350/350 [==============================] - 394s 1s/step - loss: 0.1628 - accuracy: 0.9432 - val_loss: 0.2201 - val_accuracy: 0.9217
Epoch 9/10
350/350 [==============================] - 393s 1s/step - loss: 0.1573 - accuracy: 0.9435 - val_loss: 0.1353 - val_accuracy: 0.9521
Epoch 10/10
350/350 [==============================] - 392s 1s/step - loss: 0.1252 - accuracy: 0.9551 - val_loss: 0.1487 - val_accuracy: 0.9504
In [28]:
scores = model.evaluate(test_tomatods)
76/76 [==============================] - 68s 241ms/step - loss: 0.1468 - accuracy: 0.9461
In [30]:
scores      #returns loss and accuracy
Out[30]:
[0.14679786562919617, 0.9461348652839661]
In [32]:
results_tomato    #history
Out[32]:
<keras.callbacks.History at 0x227f2cced90>
In [33]:
results_tomato.params
Out[33]:
{'verbose': 1, 'epochs': 10, 'steps': 350}
In [34]:
results_tomato.history.keys()
Out[34]:
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
In [36]:
accuracy = results_tomato.history['accuracy']
val_accuracy = results_tomato.history['val_accuracy']
loss = results_tomato.history['loss']
val_loss = results_tomato.history['val_loss']
In [37]:
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(range(epochs), accuracy, label='Training Accuracy')
plt.plot(range(epochs), val_accuracy, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(range(epochs), loss, label='Training Loss')
plt.plot(range(epochs), val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
In [44]:
import numpy as np
for images_batch, labels_batch in test_tomatods.take(1):    # where 1 is the number of batches
    #print(images_batch[0])    #Tensor format
    #print(images_batch[0].numpy())     #Numpy format
    #plt.imshow(images_batch[0].numpy().astype('uint8'))    #Displays the actual image
    first_image = images_batch[0].numpy().astype('uint8')
    first_label = labels_batch[0].numpy()
    
    print("Predicting the first image")
    plt.imshow(first_image)
    print("Actual class label:",class_names_tomato[first_label])
    
    batch_prediction = model.predict(images_batch)
    print("Predicted class label:",class_names_tomato[np.argmax(batch_prediction[0])])
Predicting the first image
Actual class label: Tomato_Septoria_leaf_spot
Predicted class label: Tomato_Septoria_leaf_spot
In [45]:
#Creating a function for inference
def predict_model(model, img):
    img_array = tf.keras.preprocessing.image.img_to_array(images[i].numpy())
    img_array = tf.expand_dims(img_array, 0)
    predictions = model.predict(img_array)
    predicted_class = class_names_tomato[np.argmax(predictions[0])]
    confidence = round(100 * (np.max(predictions[0])), 2)
    return predicted_class, confidence
In [49]:
#Running the inference on few sample images
plt.figure(figsize=(15, 15))
for images, labels in test_tomatodataset.take(1):   #Taking 1 batch
    for i in range(3):    #Considering 9 images at a time
        ax = plt.subplot(3, 1, i + 1)
        plt.imshow(images[i].numpy().astype("uint8"))
        
        predicted_class, confidence = predict_model(model, images[i].numpy())
        actual_class = class_names_tomato[labels[i]] 
        
        plt.title(f"Actual class label: {actual_class},\n Predicted class label: {predicted_class}.\n Confidence: {confidence}%")
        plt.axis("off")   #Removing the axes